package edu.udel.mboch.towerdefense;

import java.io.Serializable;
import java.util.ArrayList;

public abstract class Mob implements Serializable
{
	private static final long serialVersionUID = 1176876779102627240L;
	public static final int BASIC_COST = 20;
	public static final int FAST_COST = 40;
	public static final int HEAVY_COST = 100;
	public static final int BOSS_COST = 1000;
	
	
	protected FloatingPosition position;
	protected ArrayList<PathPosition> path;
	protected PathPosition previousPoint;
	protected int health;
	protected float speed; //Speed is in milliseconds. i.e. a speed of 1000 means 1 move per 1000 milliseconds (1 move/sec), 500 means 2 moves/sec.
	protected int bounty;
	protected int income;
	protected int cost;
	protected long timer;
	protected String name;
	protected Player player;
	protected int maxHealth;
	protected boolean slowed;
	protected long slowTimer;
	
	public Mob(FloatingPosition position, ArrayList<PathPosition> path, Player player)
	{
		this.position = position;
		timer = 0;
		this.path = new ArrayList<PathPosition>();
		for(PathPosition p : path)
			this.path.add(p);
		this.player = player;
		previousPoint = new PathPosition((int)position.x(), (int)position.y(), 0);
		slowTimer = 0;
		slowed = false;
	}
	
	public int getDistanceToEnd()
	{
		return path.size();
	}
	
	public int getHealth()
	{
		return health;
	}
	
	public int getMaxHealth()
	{
		return maxHealth;
	}
	
	public float getSpeed()
	{
		return speed;
	}
	
	public int getBounty()
	{
		return bounty;
	}
	
	public String getName()
	{
		return name;
	}
	
	public int getCost()
	{
		return cost;
	}
	
	public boolean isSlowed()
	{
		return slowed;
	}
	
	public void setPosition(FloatingPosition position)
	{
		this.position = position;
	}
	
	public void moveTo(FloatingPosition position)
	{
		this.position = position;
	}
	
	public FloatingPosition getPosition()
	{
		return position;
	}
	
	public int getIncome()
	{
		return income;
	}
	
	public Player getPlayer()
	{
		return player;
	}
	
	public void damage(int damage, TDState state)
	{
		health -= damage;
		if(health<=0)
		{
			player.addCash(bounty);
			state.getGrid().removeMob(this);
		}
	}
	
	public void slow()
	{
		slowed = true;
		slowTimer = 2000;
	}
	
	public void addTime(long time)
	{
		timer += time;
		if(slowed)
			slowTimer-=time;
		if(slowTimer<=0)
		{
			slowed = false;
			slowTimer = 0;
		}
	}
	
	public void resetTime()
	{
		timer = 0;
	}
	
	public void advanceMob(TDState state)
	{
		PathPosition nextPoint = path.get(0);
		float[] vector = previousPoint.vectorTowards(nextPoint);
		Position oldPos = position.toPosition();
		if(!slowed)
			position = new FloatingPosition((float)(position.x() + vector[0]*timer/speed), (float)(position.y() + vector[1]*timer/speed));
		else
			position = new FloatingPosition((float)(position.x() + vector[0]*timer/speed/2), (float)(position.y() + vector[1]*timer/speed/2));
		if(vector[0] == -1 && position.x() < nextPoint.x())
		{
			if(vector[1] == -1 && position.y() < nextPoint.y())
			{
				previousPoint = path.remove(0);
				position.y(previousPoint.y());
				position.x(previousPoint.x());
			}
			else if(vector[1] == 1 && position.y() > nextPoint.y())
			{
				previousPoint = path.remove(0);
				position.y(previousPoint.y());
				position.x(previousPoint.x());
			}
			else if(vector[1] == 0 && position.y() == nextPoint.y())
			{
				previousPoint = path.remove(0);
				position.x(previousPoint.x());
			}
		}
		else if(vector[0] == 1 && position.x() > nextPoint.x())
		{
			if(vector[1] == -1 && position.y() < nextPoint.y())
			{
				previousPoint = path.remove(0);
				position.y(previousPoint.y());
				position.x(previousPoint.x());
			}
			else if(vector[1] == 1 && position.y() > nextPoint.y())
			{
				previousPoint = path.remove(0);
				position.y(previousPoint.y());
				position.x(previousPoint.x());
			}
			else if(vector[1] == 0 && position.y() == nextPoint.y())
			{
				previousPoint = path.remove(0);
				position.x(previousPoint.x());
			}
		}
		else if(vector[0] == 0 && position.x() == nextPoint.x())
		{
			if(vector[1] == -1 && position.y() < nextPoint.y())
			{
				previousPoint = path.remove(0);
				position.y(previousPoint.y());
			}
			else if(vector[1] == 1 && position.y() > nextPoint.y())
			{
				previousPoint = path.remove(0);
				position.y(previousPoint.y());
			}
			else if(vector[1] == 0 && position.y() == nextPoint.y())
			{
				previousPoint = path.remove(0);
			}
		}
		if(position.x() >= Grid.MAX_X)
			position.x(Grid.MAX_X-1);
		else if(position.x() < 0)
			position.x(0);
		if(position.y() >= Grid.MAX_Y)
			position.y(Grid.MAX_Y-1);
		else if(position.y() < 0)
			position.y(0);
		state.getGrid().updateMob(oldPos, this);
		if(path.size() == 0)
		{
			player.takeLife();
			state.getGrid().removeMob(this);
		}
		timer = 0;
	}
	
	public abstract Mob copy();
	
	public abstract void print();
	
	public String toString()
	{
		return position.toString();
	}
}
